package com.qianfeng.chinamobile.api.service.impl;


//
//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖镇楼            BUG辟易  
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  


import com.qianfeng.chinamobile.api.bean.CheckResultBean;
import com.qianfeng.chinamobile.api.dto.SmsParamBody;
import com.qianfeng.chinamobile.api.dto.SmsParamBodyContent;
import com.qianfeng.chinamobile.api.dto.SmsParamBodyTemp;
import com.qianfeng.chinamobile.api.event.SendMessageEvent;
import com.qianfeng.chinamobile.api.exceptions.MyExceptionWithData;
import com.qianfeng.chinamobile.api.feign.CacheService;
import com.qianfeng.chinamobile.api.service.SmsService;
import com.qianfeng.chinamobile.api.utils.PhoneFormatCheckUtil;
import com.qianfeng.smsplatform.common.constants.CacheConstants;
import com.qianfeng.smsplatform.common.constants.InterfaceExceptionDict;
import com.qianfeng.smsplatform.common.exceptions.MyBaseException;
import com.qianfeng.smsplatform.common.model.Standard_Submit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.ObjectUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * Created by jackiechan on 2021/11/11 15:47
 *
 * @author jackiechan
 * @version 1.0
 * //TODO 给最美丽的芳姐介绍学生
 * @since 1.0
 */

@Service
public class SmsServiceImpl implements SmsService {


    private ApplicationContext context;

    @Autowired
    public void setContext(ApplicationContext context) {
        this.context = context;
    }

    private CacheService cacheService;

    @Autowired
    public void setCacheService(CacheService cacheService) {
        this.cacheService = cacheService;
    }

    @Override
    public void sendMsgByContent(SmsParamBodyContent bodyContent, String ip) {
        CheckResultBean checkResultBean = checkData(bodyContent, ip);
        //如果没有异常,就继续进行
        //封装数据,需要知道用户的类型

        List<String> failPhones = checkResultBean.getFailPhones();
        List<Standard_Submit> standardSubmits = checkResultBean.getStandard_submitList();//正常的数据
        //继续后面的操作,可以通过异步发送消息,不用让客户等待
        context.publishEvent(new SendMessageEvent(standardSubmits));
        //如果有有问题的手机号,则通知用户
        if (failPhones != null && failPhones.size() > 0) {
            MyExceptionWithData exception = new MyExceptionWithData("非法手机号或者对应内容为空", InterfaceExceptionDict.RETURN_STATUS_MOBILE_ERROR);
            exception.setData(failPhones);
            throw exception;
        }
    }

    @Override
    public CheckResultBean checkData(SmsParamBody body, String ip) {
        System.err.println("来访者的 ip" + ip);
        CheckResultBean checkResultBean = new CheckResultBean();//返回结果
        String srcId = body.getSrcId();
        if (ObjectUtils.isEmpty(srcId)) {
            //
            System.err.println("srcid 没有传递");
            throw new MyBaseException("未传递短信 id", InterfaceExceptionDict.RETURN_STATUS_SRCID_ERROR);
        }

        //先检查手机号,因为手机号在本地,不需要经过网络
        String phoneNums = body.getPhoneNums();
        if (ObjectUtils.isEmpty(phoneNums)) {
            System.err.println("手机号是空的,应该返回结果给用户");
            throw new MyBaseException("需要传递手机号", InterfaceExceptionDict.RETURN_STATUS_MOBILE_ERROR);
        }
        String[] nums = phoneNums.split(",");//手机号的数组
        List<String> numsList = Arrays.asList(nums);
        Map<String, String> phone2ContentMap = new HashMap<>();//保存手机号和对应内容的 map
        if (body instanceof SmsParamBodyContent) {
            //如果短信的内容不止一个,需要和手机号的数量进行匹配,不然不知道哪个内容对应哪个手机号
            //原本一个手机号对应了一个短信内容,但是我们发现手机号出现了非法手机号的情况,导致短信内容多了,需要移除对应的内容
            List<String> content = ((SmsParamBodyContent) body).getContent();
            //如果内容是空的,就抛出异常
            //集合本身是长度 0,或者集合内部有信息的长度是 0
            if (ObjectUtils.isEmpty(content)) {
                //空的
                throw new MyBaseException("短信内容为空",InterfaceExceptionDict.RETURN_STATUS_MESSAGE_ERROR);
            }
            //内容是空的,分两种情况, 如果只有一个内容,是空的不发送,如果是多个内容中有部分是空的
            if (content.size() == 1) {
                String msg = content.get(0);
                if (ObjectUtils.isEmpty(msg)) {
                    //内容是空的,直接返回异常
                    throw new MyBaseException("短信内容为空", InterfaceExceptionDict.RETURN_STATUS_MESSAGE_ERROR);
                }
                numsList.forEach(num -> {//全部保存到 map 中
                    phone2ContentMap.put(num, msg);
                });
            } else {
                if (numsList.size() != content.size()) {
                    //短信的数量和手机号的数量不匹配
                    throw new MyBaseException("内容和手机号不匹配", InterfaceExceptionDict.RETURN_STATUS_MESSAGE_PHONE_NOT_MATCH);
                } else {
                    //长度匹配
                    //但是可能存在部分内容是空的
                    for (int i = content.size() - 1; i >= 0; i--) {
                        phone2ContentMap.put(numsList.get(i), content.get(i));//先保存到 map 中,后面遍历处理,不管 key 有问题还是 value 有问题都移除
                    }
                }
            }
        } else if (body instanceof SmsParamBodyTemp) {
            //属于模板的
            //根据模板 id 查询模板,需要判断能不能用,不是自己的不能用,可以使用公共的
        }
        //如果传递的 srcid 重复了,也不行
        //TODO 根据 srcid 查询一下,看看有没有重复,需要知道数据保存在什么地方
        List<String> failPhone = new ArrayList<>();//保存不合法的手机号,用于通知用户结果的
        //遍历 map
        phone2ContentMap.forEach((key, value) -> {
            //手机号是非法手机号或者是短信内容是空的
            if (ObjectUtils.isEmpty(value) || !PhoneFormatCheckUtil.isChinaPhoneLegal(key)) {
                //手机号或者对应的内容不合法
                failPhone.add(key);//保存不合法的手机号
            }
        });
        failPhone.forEach(num -> {
            phone2ContentMap.remove(num);//从存有手机号和短信内容映射的集合中删除相关的不合法的手机号
        });

        System.err.println(failPhone);
        System.err.println(phone2ContentMap);
        if (failPhone.size() > 0) {
            //有需要告诉用户结果的手机号
            //之前是抛出异常,后面发现抛了之后正常的手机号也不再发送了,所以不能抛,只能返回结果给用户
            checkResultBean.setFailPhones(failPhone);
        }

        //检查用户信息,用户信息在别的地方保存,必须通过网络请求才可以获取到, 如果先检查用户信息,万一手机号有错误,就浪费一次网络的时间
        //我们要获取到用户信息,假如保存到 redis, key 是什么?以用户的唯一标识作为 key
        //
        Map userinfoMap = cacheService.hmget(CacheConstants.CACHE_PREFIX_CLIENT + body.getUsercode());//从 redis 中获取用户的信息
        if (userinfoMap == null) {
            //没有查询到用户信息
            //要干什么? 比如我们确定所有的用户数据都是缓存中,查不到就是没有,要是不确定呢? 要是只保存了一部分呢
            //查询数据源,如果数据源也查询不到就返回(通过防穿透过滤掉无效请求,只要查询数据源就一定有结果)
            throw new MyBaseException("认证失败", InterfaceExceptionDict.RETURN_STATUS_CLIENTID_ERROR);

        }
        String password = body.getPassword();//传递的密码
        String pwd = (String) userinfoMap.get("pwd");//保存的密码,但是是一个 md5 值
        //密码进行转换,将用户传递的密码转换为 md5
        String md5 = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
        if (!md5.equalsIgnoreCase(pwd)) {
            //密码不一致
            //返回结果
            throw new MyBaseException("认证失败",InterfaceExceptionDict.RETURN_STATUS_CLIENTID_ERROR);
        }
        String ipAddress = (String) userinfoMap.get("ipaddress");//用户允许使用的 ip 地址
        if (!ipAddress.contains(ip)) {
            //不在允许的 ip 列表中
            throw new MyBaseException("非白名单ip", InterfaceExceptionDict.RETURN_STATUS_IP_ERROR);
        }
        //生成数据
        List<Standard_Submit> standard_submits = new ArrayList<>();
        phone2ContentMap.forEach((num, content) -> {
            Standard_Submit standard_submit = new Standard_Submit();
            standard_submit.setClientID(body.getUsercode());
            standard_submit.setDestMobile(num);
            standard_submit.setMessageContent(content);
            standard_submit.setSrcNumber(srcId);
            standard_submit.setSendTime(new Date());
            standard_submit.setSource((Integer) userinfoMap.get("usertype"));//设置用户的类型,是 1 的话后续需要通知对方
            standard_submits.add(standard_submit);
        });
        checkResultBean.setStandard_submitList(standard_submits);
        return checkResultBean;
    }
}
